package com.zzs.server.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zzs.common.core.entity.mysql.ProblemCodeDO;
import com.zzs.common.core.entity.mysql.TestCaseDO;
import com.zzs.common.core.entity.redis.ProblemCache;
import com.zzs.common.core.entity.redis.ProblemCodeCache;
import com.zzs.common.core.entity.redis.TestCaseCache;
import com.zzs.common.core.enums.ProblemStatus;
import com.zzs.common.core.enums.ResponseCode;
import com.zzs.common.core.response.PageResult;
import com.zzs.common.core.util.SnowflakeUtil;
import com.zzs.common.security.exception.ServiceException;
import com.zzs.server.dao.mysql.ProblemCodeMapper;
import com.zzs.server.dao.mysql.ProblemMapper;
import com.zzs.server.dao.mysql.TestCaseMapper;
import com.zzs.common.core.entity.mysql.ProblemDO;
import com.zzs.server.dao.redis.ProblemCacheManager;
import com.zzs.server.dao.redis.ProblemCodeCacheManager;
import com.zzs.server.dao.redis.TestCaseCacheManager;
import com.zzs.server.pojo.bo.problem.SaveProblemBO;
import com.zzs.server.pojo.bo.problem.UpdateProblemBO;
import com.zzs.server.pojo.query.ProblemQuery;
import com.zzs.server.pojo.vo.ProblemDetailVO;
import com.zzs.server.pojo.vo.ProblemVO;
import com.zzs.server.service.ProblemService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;


/**
 * @author zzs
 * @date 2025/03/17
 */
@Service
public class ProblemServiceImpl implements ProblemService {
    @Autowired
    private ProblemMapper problemMapper;
    @Autowired
    private ProblemCodeMapper problemCodeMapper;
    @Autowired
    private TestCaseMapper testCaseMapper;
    @Autowired
    private ProblemCacheManager problemCacheManager;
    @Autowired
    private ProblemCodeCacheManager problemCodeCacheManager;
    @Autowired
    private TestCaseCacheManager testCaseCacheManager;

    @Override
    public long saveProblem(SaveProblemBO saveProblemBO) {
        ProblemDO problemDO = new ProblemDO();
        BeanUtils.copyProperties(saveProblemBO, problemDO);
        problemDO.setStatus(ProblemStatus.NOT_PUBLISH.getStatus());
        long id = SnowflakeUtil.nextId();
        problemDO.setId(id);
//        保存到mysql
        int effectRows = problemMapper.save(problemDO);
        if (effectRows != 1) {
            throw new ServiceException(ResponseCode.NOT_FOUND, "题目保存失败");
        }
        return id;
    }

    @Override
    public void updateProblem(UpdateProblemBO updateProblemBO) {
        ProblemDO problemDO = new ProblemDO();
        BeanUtils.copyProperties(updateProblemBO, problemDO);
//        只有存在, 且处于未发布状态的题目才能更新
        int effectRows = problemMapper.update(problemDO);
        if (effectRows != 1) {
//            题目id是唯一的，所以根据题目id来修改，影响的行数一定是1.
            throw new ServiceException(ResponseCode.NOT_FOUND, "题目处于发布状态或不存在");
        }
    }

    @Override
    public ProblemDetailVO getProblem(long problemId) {
        ProblemDO problemDO = problemMapper.get(problemId);
        if (problemDO == null) {
            throw new ServiceException(ResponseCode.NOT_FOUND);
        }
        ProblemDetailVO problemDetailVO = new ProblemDetailVO();
        BeanUtils.copyProperties(problemDO, problemDetailVO);
        return problemDetailVO;
    }

    @Override
    public void removeProblem(long problemId) {
//        只有处于未发布状态的题目才能删除
        boolean publish = problemMapper.isPublish(problemId);
        if (publish) {
            throw new ServiceException(ResponseCode.ACCESS_DENIED, "只有未发布的题目才能删除");
        }
        testCaseMapper.removeByProblemId(problemId);
        problemCodeMapper.removeByProblemId(problemId);
        int effectRows = problemMapper.remove(problemId);
        if (effectRows != 1) {
            throw new ServiceException(ResponseCode.NOT_FOUND);
        }
    }

    @Override
    public PageResult<ProblemVO> listProblems(ProblemQuery problemQuery) {
        System.out.println(problemQuery);
        PageHelper.startPage(problemQuery.getPageNum(), problemQuery.getPageSize());
        List<ProblemDO> problemDOList = problemMapper.listProblems(problemQuery.getDifficulty(), problemQuery.getKeyword());
        // 使用 PageInfo 封装分页信息
        PageInfo<ProblemDO> pageInfo = new PageInfo<>(problemDOList);
        // 将 ProblemDO 转换为 ProblemVO
        List<ProblemVO> rows = problemDOList.stream()
                .map(problemDO -> {
                    ProblemVO problemVO = new ProblemVO();
                    BeanUtils.copyProperties(problemDO, problemVO);
                    return problemVO;
                }).toList();
        // 返回分页结果
        return PageResult.success((int) pageInfo.getTotal(), rows);
    }

    @Override
    public void publishProblem(long problemId) {
        boolean existsCode = problemCodeMapper.existsByProblemId(problemId);
        if (!existsCode) {
            throw new ServiceException(ResponseCode.NOT_FOUND, "没有代码内容的题目不能发布");
        }
        boolean existsCase = testCaseMapper.existsByProblemId(problemId);
        if (!existsCase) {
            throw new ServiceException(ResponseCode.NOT_FOUND, "没有测试用例的题目不能发布");
        }
        int effectRows = problemMapper.setStatus(problemId, ProblemStatus.PUBLISH.getStatus());
        if (effectRows != 1) {
//            通过id修改status，影响的行数一定是1，如果不为1，那说明操作失败了
            throw new ServiceException(ResponseCode.NOT_FOUND, "发布题目失败");
        }
//        保存缓存, 缓存中的题目一定是发布的
        saveCache(problemId);
    }

    @Override
    public void cancelProblem(long problemId) {
        int effectRows = problemMapper.setStatus(problemId, ProblemStatus.NOT_PUBLISH.getStatus());
        if (effectRows != 1) {
            throw new ServiceException(ResponseCode.NOT_FOUND, "撤销题目失败");
        }
//        题目撤销发布, 要删除缓存
        removeCache(problemId);
    }

    @Override
    public void checkExistsAndPublish(long problemId) {
        boolean exists = problemMapper.exists(problemId);
        if (!exists) {
            throw new ServiceException(ResponseCode.NOT_FOUND, "题目不存在");
        }
        boolean publish = problemMapper.isPublish(problemId);
        if (publish) {
            throw new ServiceException(ResponseCode.ACCESS_DENIED, "题目已经发布");
        }
    }

    private void saveCache(long problemId) {
//        保存题目缓存
        ProblemDO problemDO = problemMapper.get(problemId);
        ProblemCache problemCache = new ProblemCache();
        BeanUtils.copyProperties(problemDO, problemCache);
        problemCacheManager.save(problemCache);
//        保存题目的测试用例缓存
        TestCaseDO testCaseDO = testCaseMapper.get(problemId);
        TestCaseCache testCaseCache = new TestCaseCache();
        BeanUtils.copyProperties(testCaseDO, testCaseCache);
        testCaseCacheManager.save(testCaseCache);
//        保存题目的代码缓存
        List<ProblemCodeDO> problemCodeDOList = problemCodeMapper.list(problemId);
        for (ProblemCodeDO problemCodeDO : problemCodeDOList) {
            ProblemCodeCache problemCodeCache = new ProblemCodeCache();
            BeanUtils.copyProperties(problemCodeDO, problemCodeCache);
            problemCodeCacheManager.save(problemCodeCache);
        }
    }

    private void removeCache(long problemId) {
//        删除题目缓存
        problemCacheManager.remove(problemId);
//        删除题目的测试用例缓存
        testCaseCacheManager.remove(problemId);
//        删除题目的代码缓存
        List<Integer> languageList = problemCodeMapper.listLanguage(problemId);
        for (int language : languageList) {
            problemCodeCacheManager.remove(problemId, language);
        }
    }
}
